package ph.com.gs3.formalistics.presenter.fragements.workers;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import ph.com.gs3.formalistics.global.constants.DocumentType;
import ph.com.gs3.formalistics.global.constants.StarMark;
import ph.com.gs3.formalistics.global.utilities.DocumentUtilities;
import ph.com.gs3.formalistics.global.utilities.logging.FLLogger;
import ph.com.gs3.formalistics.model.facades.DocumentsDataReader;
import ph.com.gs3.formalistics.model.facades.DocumentsDataWriter;
import ph.com.gs3.formalistics.model.facades.FormsDataReader;
import ph.com.gs3.formalistics.model.facades.OutgoingActionDataReader;
import ph.com.gs3.formalistics.model.facades.OutgoingActionDataWriter;
import ph.com.gs3.formalistics.model.vo.business.User;
import ph.com.gs3.formalistics.model.vo.business.document.Document;
import ph.com.gs3.formalistics.model.vo.business.document.OutgoingAction;
import ph.com.gs3.formalistics.model.vo.business.form.Form;
import android.app.Fragment;
import android.content.Context;

public class DocumentWorkerFragment extends Fragment {

	public static final String TAG = DocumentWorkerFragment.class.getSimpleName();

	// Data fields
	private Form currentForm;
	private Document currentDocument;
	private OutgoingAction currentOutgoingAction;
	private User currentUser;
	private DocumentType documentType;

	private int parentDocumentId;
	
	private OutgoingActionDataReader outgoingActionDataReader;
	private FormsDataReader formsDataReader;
	private DocumentsDataReader documentsDataReader;

	private DocumentsDataWriter documentsDataWriter;
	private OutgoingActionDataWriter outgoingActionDataWriter;

	public static DocumentWorkerFragment createInstance(Context context, User currentUser) {

		DocumentWorkerFragment instance = new DocumentWorkerFragment();
		instance.initializeDependencies(context);
		instance.currentUser = currentUser;

		return instance;

	}

	private void initializeDependencies(Context context) {

		outgoingActionDataReader = new OutgoingActionDataReader(context);
		formsDataReader = new FormsDataReader(context, currentUser);
		documentsDataReader = new DocumentsDataReader(context);

		documentsDataWriter = new DocumentsDataWriter(context, currentUser);
		outgoingActionDataWriter = new OutgoingActionDataWriter(context);

	}

	public void initialize(DocumentType documentType, int formId, int documentId,
	        int parentDocumentId) {

		this.documentType = documentType;
		this.parentDocumentId = parentDocumentId;
		currentForm = formsDataReader.getForm(formId);

		switch (documentType) {
			case NEW_DOCUMENT:
			case CHILD_DOCUMENT:
				currentDocument = DocumentUtilities.createNewBlankDocument(formId,
				        currentUser.getId());
				break;
			case EXISTING_DOCUMENT:
				currentDocument = documentsDataReader.getDocument(documentId);
				// Null if no outgoing action
				currentOutgoingAction = outgoingActionDataReader
				        .getOutgoingActionByDocumentId(documentId);
				break;
			case OUTGOING_DOCUMENT:
				currentOutgoingAction = outgoingActionDataReader
				        .getOutgoingActionByDocumentId(documentId);
				// Null if no document
				currentDocument = currentOutgoingAction.getDocument();
				break;
		}

	}

	public void saveDocumentAction(JSONObject documentFieldValues, String action) {

		int formId = currentForm.getId();

		FLLogger.d(TAG, "documentType: " + documentType);
		
		switch (documentType) {
			case NEW_DOCUMENT:
				outgoingActionDataWriter.saveDocumentAction(0, formId, documentFieldValues, action,
				        currentUser);
				break;
			case EXISTING_DOCUMENT:
				int documentId = currentDocument.getId();
				outgoingActionDataWriter.saveDocumentAction(documentId, formId,
				        documentFieldValues, action, currentUser);
				break;
			case OUTGOING_DOCUMENT:
				FLLogger.d(TAG, "Add a cancel action for outgoing documents");
				break;
			case CHILD_DOCUMENT:
				outgoingActionDataWriter.saveDocumentAction(0, formId, documentFieldValues, action,
				        currentUser, parentDocumentId);
				break;
		}

	}

	public void markDocumentStar(StarMark starMark) {

		int documentId = currentDocument.getId();
		int formId = currentDocument.getFormId();

		outgoingActionDataWriter.saveStarMark(documentId, formId, starMark, currentUser);
		documentsDataWriter.changeDocumentStarMark(documentId, starMark);

		currentDocument.setStarMark(starMark);

	}

	public List<String> validateFields(JSONObject updatedFieldValues) {
		List<String> fieldsThatFailedValidation = new ArrayList<>();
		List<String> fieldsRequired = new ArrayList<>();

		if (documentType == DocumentType.NEW_DOCUMENT) {
			fieldsRequired = currentForm.getOnCreateFieldsRequired();
		} else if (documentType == DocumentType.EXISTING_DOCUMENT) {
			fieldsRequired = currentDocument.getFieldsRequired();
		}

		for (String requiredField : fieldsRequired) {

			boolean passed = false;
			if (updatedFieldValues.has(requiredField)) {
				String fieldValue;
				try {
					fieldValue = updatedFieldValues.getString(requiredField);
					if (fieldValue != null && !fieldValue.trim().isEmpty()) {
						passed = true;
					}
				} catch (JSONException e) {
					// Failed, print exception
					e.printStackTrace();
				}
			}

			if (!passed) {
				fieldsThatFailedValidation.add(requiredField);
			}
		}
		return fieldsThatFailedValidation;
	}

	public boolean hasNewChildOutgoingActions() {
		return outgoingActionDataReader.hasNewChildOutgoingActions();
	}

	public void clearOrphanedOutgoingActions() {
		outgoingActionDataWriter.clearOrphanedOutgoingActions();
	}

	public void updateChildOutgoingActionsForSubmition() {
		outgoingActionDataWriter.updateChildOutgoingActionsForSubmition(currentDocument.getId());
	}

	public Form getCurrentForm() {
		return currentForm;
	}

	public Document getCurrentDocument() {
		return currentDocument;
	}

	public OutgoingAction getOutgoingAction() {
		return currentOutgoingAction;
	}

}
